# -*- coding: utf-8 -*-
"""Controlador de Analizadores Lexicos"""

from tg import expose, flash, require, url, request, redirect
from pylons.i18n import ugettext as _, lazy_ugettext as l_
from tgext.admin.tgadminconfig import TGAdminConfig
from tgext.admin.controller import AdminController, AdminConfig
from repoze.what import predicates
from tg import tmpl_context, validate
from webhelpers import paginate
from sqlalchemy import func
from sqlalchemy.exc import IntegrityError, SQLAlchemyError
import transaction

from lex.lib.base import BaseController
from lex.model import metadata, DBSession
from lex.model.model import AnalizadorLexico, Alfabeto
from lex import model
from lex.widgets import analizadores_form
from lex.widgets.analizadores_form import crear_analizador_form, editar_analizador_form

__all__ = ['AnalizadoresController']

class AnalizadoresController(BaseController):

    @expose("lex.templates.analizadores.listado_analizadores")
    def listado_analizadores(self,page=1):
        """Metodo para listar todos los Analizadores existentes en la base de datos"""
        try:
            #Obtenemos todos los objetos "AnalizadorLexico".
            analizadores = DBSession.query(AnalizadorLexico).order_by(AnalizadorLexico.id_analizador_lexico)
            currentPage = paginate.Page(analizadores, page, items_per_page=10)
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Analizadores! SQLAlchemyError..."), 'error')
            redirect("/admin")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Analizadores! Hay Problemas con el servidor..."), 'error')
            redirect("/admin")
    
        return dict(analizadores=currentPage.items, currentPage=currentPage)      

    @expose('lex.templates.analizadores.nuevo_analizador')
    def nuevo_analizador(self, **kw):
        """Despliega el formulario para añadir un nuevo Analizador Lexico"""
        try:
            #Establecemos el contexto de nuestro formulario de creacion de analizador lexico.
            tmpl_context.form = crear_analizador_form
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Creacion de Analizadores! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Creacion de Analizador! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")

        return dict(nombre_modelo='Analizador Lexico', value=kw)

    @validate(crear_analizador_form, error_handler=nuevo_analizador)
    @expose()
    def add(self, **kw):
        """Metodo para agregar un registro a la base de datos """
        try:
            #Realizamos algunas comprobaciones del nombre del analizador.
            nombre_analizador = kw['nombre_analizador_lexico']
            lista_nombre = nombre_analizador.split()
            nombre_analizador = " ".join(lista_nombre)

            #Creamos un nuevo analizador lexico e insertamos en la BD.
            analizador = AnalizadorLexico()
            analizador.nombre_analizador_lexico = nombre_analizador
            analizador.estado = False
            DBSession.add(analizador)

            #Por defecto se le agregan dos alfabetos predeterminados.
            id_alfabeto1 = 1
            id_alfabeto2 = 2
            alfabeto1 = DBSession.query(Alfabeto).get(id_alfabeto1)
            alfabeto2 = DBSession.query(Alfabeto).get(id_alfabeto2)
            analizador.alfabetos.append(alfabeto1)
            analizador.alfabetos.append(alfabeto2)

            #Confirmamos la transaccion.
            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            flash(_("No se ha guardado! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except SQLAlchemyError:
            flash(_("No se ha guardado! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except (AttributeError, NameError):
            flash(_("No se ha guardado! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")
        else:
            flash(_("Analizador creado!"), 'ok')
    
        redirect("/analizadores/listado_analizadores")

    @expose('lex.templates.analizadores.editar_analizador')
    def editar_analizador(self, id_analizador_lexico, **kw):
        """Metodo que rellena el formulario para editar un Analizador Lexico"""
        try:
            #Establecemos el contexto del formulario de edicion de analizadores lexicos.
            tmpl_context.form = editar_analizador_form

            #Cargamos el formulario con los datos del analizador lexico a editar.
            analizador = DBSession.query(AnalizadorLexico).get(id_analizador_lexico)
            kw['id_analizador_lexico'] = analizador.id_analizador_lexico
            kw['nombre_analizador_lexico'] = analizador.nombre_analizador_lexico
            kw['estado'] = analizador.estado
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Edicion de Analizadores! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Edicion de Analizadores! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")

        return dict(value=analizador)

    @validate(editar_analizador_form, error_handler=editar_analizador)
    @expose()
    def update(self, **kw):        
        """Metodo que actualizar la base de datos"""
        try:
            #Realizamos algunas comprobaciones del nombre del analizador.
            nombre_analizador = kw['nombre_analizador_lexico']
            lista_nombre = nombre_analizador.split()
            nombre_analizador = " ".join(lista_nombre)

            #Guardamos los cambios realizados en la edicion del analizador lexico.
            analizador = DBSession.query(AnalizadorLexico).get(kw['id_analizador_lexico'])
            analizador.nombre_analizador_lexico = nombre_analizador
            analizador.estado = kw['estado']

            #Confirmamos la transaccion
            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            flash(_("No se han guardado los cambios! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except SQLAlchemyError:
            flash(_("No se han guardado los cambios! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except (AttributeError, NameError):
            flash(_("No se han guardado los cambios! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")
        else:
            flash(_("Se han guardado los cambios!"), 'ok')

        redirect("/analizadores/listado_analizadores")

    @expose('lex.templates.analizadores.confirmar_eliminar_analizador')
    def confirmar_eliminar_analizador(self, id_analizador_lexico, **kw):
        """Despliega confirmacion de eliminacion"""
        try:
            #Se muestran los datos del analizador lexico seleccionado.
            analizador = DBSession.query(AnalizadorLexico).get(id_analizador_lexico)
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Eliminacion de Analizadores! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Eliminacion de Analizadores! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")

        return dict(value=analizador)

    @expose()
    def delete(self, id_analizador_lexico, **kw):
        """Metodo que elimina un registro de la base de datos"""
        try:
            #Al eliminar un analizador se debe eliminar recursivamente todos sus datos adjuntos.
##########################################################



##########################################################
            DBSession.delete(DBSession.query(AnalizadorLexico).get(id_analizador_lexico))
            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            flash(_("No se ha eliminado! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except SQLAlchemyError:
            flash(_("No se ha eliminado! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except (AttributeError, NameError):
            flash(_("No se ha eliminado! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")
        else:
            flash(_("Analizador eliminado!"), 'ok')

        redirect("/analizadores/listado_analizadores")

    @expose("lex.templates.analizadores.listar_alfabetos")
    def listar_alfabetos(self, id_analizador_lexico, page=1):
        """Metodo para listar todos los alfabetos que tiene el analizador seleccionado"""
        try:
            #Se obtienen todos los alfabetos que forman parte del analizador lexico.
            analizador = DBSession.query(AnalizadorLexico).get(id_analizador_lexico)
            alfabetos = analizador.alfabetos
            currentPage = paginate.Page(alfabetos, page, items_per_page=10)
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Alfabetos del Analizador Lexico! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listado_analizadores")
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Alfabetos del Analizador Lexico! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listado_analizadores")

        return dict(alfabetos=currentPage.items, currentPage=currentPage, analizador=analizador)

    @expose()
    def eliminar_analizador_alfabeto(self, id_analizador_lexico, id_alfabeto, **kw):
        """Metodo que elimina un alfabeto del analizador seleccionado"""
        try:
            #Se desasigna un alfabeto que formaba parte del analizador lexico.
            analizador = DBSession.query(AnalizadorLexico).get(id_analizador_lexico)
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
            
            if analizador.alfabetos.count(alfabeto) >= 1: 
               analizador.alfabetos.remove(alfabeto)

            DBSession.flush()
            transaction.commit()
        except IntegrityError:
            transaction.abort()
            flash(_("No se pudo desasignar el Alfabeto! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listar_alfabetos", id_analizador_lexico=id_analizador_lexico)
        except SQLAlchemyError:
            flash(_("No se pudo desasignar el Alfabeto! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listar_alfabetos", id_analizador_lexico=id_analizador_lexico)
        except (AttributeError, NameError):
            flash(_("No se pudo desasignar el Alfabeto! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listar_alfabetos", id_analizador_lexico=id_analizador_lexico)
        except (ValueError):
            redirect("/analizadores/listar_alfabetos", id_analizador_lexico=id_analizador_lexico)
        else:
            flash(_("Alfabeto desasignado!"), 'ok')

        redirect("/analizadores/listar_alfabetos", id_analizador_lexico=id_analizador_lexico)

    @expose("lex.templates.analizadores.agregar_alfabetos")
    def agregar_alfabetos(self, id_analizador_lexico, page=1):
        """Metodo que permite listar los alfabetos que se pueden agregar al analizador seleccionado"""
        try:
            #Se obtienen todos los alfabetos que pueden formar parte del analizador lexico.
            analizador = DBSession.query(AnalizadorLexico).get(id_analizador_lexico)
            alfabetos_del_analizador = analizador.alfabetos
            alfabetos = DBSession.query(Alfabeto).all()
        
            for alfabeto_del_analizador in alfabetos_del_analizador:
                if alfabetos.count(alfabeto_del_analizador) >= 1: 
                   alfabetos.remove(alfabeto_del_analizador)

            currentPage = paginate.Page(alfabetos, page, items_per_page=10)
        except SQLAlchemyError:
            flash(_("No se pudo acceder a Asignar Alfabetos! SQLAlchemyError..."), 'error')
            redirect("/analizadores/listar_alfabetos", id_analizador_lexico=id_analizador_lexico)
        except (AttributeError, NameError):
            flash(_("No se pudo acceder a Asignar Alfabetos! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/listar_alfabetos", id_analizador_lexico=id_analizador_lexico)

        return dict(alfabetos=currentPage.items, currentPage=currentPage, analizador=analizador)

    @expose()
    def agregar_alfabeto(self, id_analizador_lexico, id_alfabeto):
        """Metodo que realiza la agregacion de un alfabeto al analizador selecccionado"""
        try:
            #Se asigna un alfabeto que no formaba parte del analizador lexico.
            analizador = DBSession.query(AnalizadorLexico).get(id_analizador_lexico)
            alfabeto = DBSession.query(Alfabeto).get(id_alfabeto)
            analizador.alfabetos.append(alfabeto)
            DBSession.flush()
            transaction.commit()
        except IntegrityError:            
            redirect("/analizadores/analizador_alfabeto",id_analizador_lexico=id_analizador_lexico)
        except SQLAlchemyError:
            flash(_("No se pudo asignar el Permiso! SQLAlchemyError..."), 'error')
            redirect("/analizadores/agregar_alfabetos",id_analizador_lexico=id_analizador_lexico)
        except (AttributeError, NameError):
            flash(_("No se pudo asignar el Permiso! Hay Problemas con el servidor..."), 'error')
            redirect("/analizadores/agregar_alfabetos",id_analizador_lexico=id_analizador_lexico)
        else:
            flash(_("Alfabeto asignado!"), 'ok')

        redirect("/analizadores/agregar_alfabetos",id_analizador_lexico=id_analizador_lexico)
